/*
Copyright 2007 John Tsiombikas <nuclear@siggraph.org>

This file is part of the pixelshow 2007 invitation demo.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#include "image.h"
#include <stdio.h>

#ifdef IMGLIB_USE_PPM

#include <stdlib.h>
#include <ctype.h>
#include "color_bits.h"


int check_ppm(FILE *fp) {
	fseek(fp, 0, SEEK_SET);
	if(fgetc(fp) == 'P' && fgetc(fp) == '6') {
		return 1;
	}
	return 0;
}

static int read_to_wspace(FILE *fp, char *buf, int bsize) {
	int c, count = 0;
	
	while((c = fgetc(fp)) != -1 && !isspace(c) && count < bsize - 1) {
		if(c == '#') {
			while((c = fgetc(fp)) != -1 && c != '\n' && c != '\r');
			c = fgetc(fp);
			if(c == '\n' || c == '\r') continue;
		}
		*buf++ = c;
		count++;
	}
	*buf = 0;
	
	while((c = fgetc(fp)) != -1 && isspace(c));
	ungetc(c, fp);
	return count;
}

void *load_ppm(FILE *fp, int *xsz, int *ysz) {
	char buf[64];
	int bytes, raw;
	unsigned int w, h, i, sz;
	uint32_t *pixels;
	
	fseek(fp, 0, SEEK_SET);
	
	bytes = read_to_wspace(fp, buf, 64);
	raw = buf[1] == '6';

	if((bytes = read_to_wspace(fp, buf, 64)) == 0) {
		return 0;
	}
	if(!isdigit(*buf)) {
		fprintf(stderr, "load_ppm: invalid width: %s\n", buf);
		return 0;
	}
	w = atoi(buf);

	if((bytes = read_to_wspace(fp, buf, 64)) == 0) {
		return 0;
	}
	if(!isdigit(*buf)) {
		fprintf(stderr, "load_ppm: invalid height: %s\n", buf);
		return 0;
	}
	h = atoi(buf);

	if((bytes = read_to_wspace(fp, buf, 64)) == 0) {
		return 0;
	}
	if(!isdigit(*buf) || atoi(buf) != 255) {
		fprintf(stderr, "load_ppm: invalid or unsupported max value: %s\n", buf);
		return 0;
	}

	if(!(pixels = malloc(w * h * sizeof *pixels))) {
		fprintf(stderr, "load_ppm: malloc failed\n");
		return 0;
	}

	sz = h * w;
	for(i=0; i<sz; i++) {
		int r = fgetc(fp);
		int g = fgetc(fp);
		int b = fgetc(fp);

		if(r == -1 || g == -1 || b == -1) {
			free(pixels);
			fprintf(stderr, "load_ppm: EOF while reading pixel data\n");
			return 0;
		}
		pixels[i] = PACK_COLOR24(r, g, b);
	}

	if(xsz) *xsz = w;
	if(ysz) *ysz = h;
	return pixels;
}

int save_ppm(FILE *fp, void *pixels, int xsz, int ysz) {
	int i, j;
	uint32_t *ptr;
	unsigned int save_flags = get_image_save_flags();

	fprintf(fp, "P%d\n%d %d\n255\n", (save_flags & IMG_SAVE_TEXT) ? 3 : 6, xsz, ysz);

	ptr = save_flags & IMG_SAVE_INVERT ? (uint32_t*)pixels + (ysz - 1) * xsz : pixels;
	for(i=0; i<ysz; i++) {
		for(j=0; j<xsz; j++) {
			int r = (ptr[j] & RED_MASK32) >> RED_SHIFT32;
			int g = (ptr[j] & GREEN_MASK32) >> GREEN_SHIFT32;
			int b = (ptr[j] & BLUE_MASK32) >> BLUE_SHIFT32;

			if(save_flags & IMG_SAVE_TEXT) {
				fprintf(fp, "%d %d %d\n", r, g, b);
			} else {
				fputc(r, fp);
				fputc(g, fp);
				if(fputc(b, fp) == EOF) {
					fprintf(stderr, "save_ppm: failed to write to file\n");
					return -1;
				}
			}
		}

		ptr += save_flags & IMG_SAVE_INVERT ? -xsz : xsz;
	}

	return 0;
}

#endif	/* IMGLIB_USE_PPM */
